#include "DataLinkedList.h"

///////////////////////////////////////////////////////////////////////////////////////////////// class DataLinkedList::Node's public methods

/***************************************************************************************
* function name: Node (Data* data)
* The Input: Data object to be set as node's data attribute
* The output: None
* The Function operation: Initializes data object pointer to given data object.
*						  Previous and next list node pointers are initialized as NULL
*						  because the new list node's position in the linked
*						  list is not set yet
***************************************************************************************/
DataLinkedList::Node::Node(Data* data) {
	m_data = data; // set data attribute to point at given data object
	// new node's position in linked list is not set yet
	m_prevListNode = NULL;
	m_nextListNode = NULL;
}

/****************************************************************************************
* function name: ~Node()
* The Input: None
* The output: None
* The Function operation: Pointed data is not deleted.
* 						  If exist, next and previous list nodes are linked
***************************************************************************************/
DataLinkedList::Node::~Node() {

	// link next node and previous node
	if (m_nextListNode != NULL) { // not end of list
		m_nextListNode->m_prevListNode = m_prevListNode;
	}
	if (m_prevListNode != NULL) { // not beginning of list
		m_prevListNode->m_nextListNode = m_nextListNode;
	}

	// TODO DEBUG PRINT!!!
	//cout << "in DataLinkedList::Node Dtor" << endl;

}

///////////////////////////////////////////////////////////////////////////////////////////////// class DataLinkedList::Iterator's protected methods



///////////////////////////////////////////////////////////////////////////////////////////////// class DataLinkedList::Iterator's public methods

/***************************************************************************************
 * function name: Iterator(DataLinkedList& dataList)
 * The Input: None
 * The output: None
 * The Function operation: Creates a new iterator for data linked list. Current node
 * 						   pointer is initialized to NULL since it is not associated
 * 						   with any list yet
 ***************************************************************************************/
DataLinkedList::Iterator::Iterator() {
	m_currNode = NULL;
}

/***************************************************************************************
 * function name: Iterator(const Iterator& itrToCopy)
 * The Input: Iterator to be copied
 * The output: None
 * The Function operation: Sets new itarator's current node pointer attribute as given
 * 						   iterator's position on its list
 ***************************************************************************************/
DataLinkedList::Iterator::Iterator(const Iterator& itrToCopy) {
	m_currNode = itrToCopy.m_currNode;
}

DataLinkedList::Node& DataLinkedList::Iterator::getNodeRef() const {
	return *m_currNode;
}

/***************************************************************************************
 * function name: ~Iterator()
 * The Input: None
 * The output: None
 * The Function operation: Empty implementation since pointed linked list is not deleted
 ***************************************************************************************/
DataLinkedList::Iterator::~Iterator() {}

DataLinkedList::Iterator& DataLinkedList::Iterator::operator ++() {
	if (m_currNode->m_nextListNode != NULL) {
		m_currNode = m_currNode->m_nextListNode;
	}
	return *this;
}

DataLinkedList::Iterator& DataLinkedList::Iterator::operator --() {
	if (m_currNode->m_prevListNode != NULL) {
		m_currNode = m_currNode->m_prevListNode;
	}
	return *this;
}

bool DataLinkedList::Iterator::operator==(const Iterator& otherIterator) const {
	return m_currNode == otherIterator.m_currNode;
}

///////////////////////////////////////////////////////////////////////////////////////////////// class DataLinkedList's protected methods

/***************************************************************************************
* function name: internalAdd(Node& newGraphNode, Node* before)
* The Input: Pointer to graph node to be added and a pointer to the list node where the
* 			 new graph node will be linked
* The output: None
* The Function operation: A new list node is created pointing to graph node to be added.
*			              Method links the new list node before the given list node and
*			              then increments next list nodes' indices
***************************************************************************************/
//void DataLinkedList::internalAdd(Data& newData, Node& before) {
void DataLinkedList::internalAdd(Data& newData, const Iterator& positionHolder) {

	Node* newNode = new Node(&newData); // create a list node pointing to new graph node
	// link list node to list
	Node* prevListNodeBackup = positionHolder.getNodeRef().m_prevListNode;
	newNode->m_nextListNode = &positionHolder.getNodeRef();
	positionHolder.getNodeRef().m_prevListNode = newNode;

	newNode->m_prevListNode = prevListNodeBackup;
	prevListNodeBackup->m_nextListNode = newNode;
}

void DataLinkedList::removeNode(const Iterator& nodeHolder) {

	// TODO DEBUG PRINT!!!
	//cout << "in DataLinkedList::removeNode" << endl;

//	// link next node and previous node - TODO added now
//	if (nodeHolder.getNodeRef().m_nextListNode != NULL) { // not end of list
//		nodeHolder.getNodeRef().m_nextListNode->m_prevListNode = nodeHolder.getNodeRef().m_prevListNode;
//	}
//	if (nodeHolder.getNodeRef().m_prevListNode != NULL) { // not beginning of list
//		nodeHolder.getNodeRef().m_prevListNode->m_nextListNode = nodeHolder.getNodeRef().m_nextListNode;
//	}
//


	// delete node being pointed by given iterator
	delete &(nodeHolder.getNodeRef());
}

void DataLinkedList::swapNodes(const Iterator& firstNodeHolder, const Iterator& secondNodeHolder) {
	// backup first node's data
	Data* firstDataCopy = *firstNodeHolder;
	firstNodeHolder.getNodeRef() = *secondNodeHolder;
	secondNodeHolder.getNodeRef() = firstDataCopy;
}


///////////////////////////////////////////////////////////////////////////////////////////////// class DataLinkedList's public methods

/***************************************************************************************
 * function name: NodeLinkedList()
 * The Input: None
 * The output: None
 * The Function operation: Initializes a new linked list holding Data objects
 ***************************************************************************************/
DataLinkedList::DataLinkedList() {

	// create dummy list nodes at list's begging and end to avoid checking NULL values
	m_headDummy = new Node(NULL);
	m_tailDummy = new Node(NULL);
	// link head and tail
	m_headDummy->m_nextListNode = m_tailDummy;
	m_tailDummy->m_prevListNode = m_headDummy;
}

/***************************************************************************************
 * function name: ~DataLinkedList()
 * The Input: None
 * The output: None
 * The Function operation: Scans list from start to end and deletes each node
 ***************************************************************************************/
DataLinkedList::~DataLinkedList() {

	// scan list and delete list nodes
	Node* currNode = m_headDummy;
	Node* prevNode = m_headDummy;

	while (currNode != NULL) {
		// move to next node on list and delete the previous which has been scanned
		currNode = currNode->m_nextListNode;
		delete prevNode;
		prevNode = currNode;
	}
	delete prevNode; // delete last node on list
}


DataLinkedList::Iterator DataLinkedList::begin() const {
	Iterator newItr;
	//newItr.setCurrNode(*m_headDummy);
	newItr = *m_headDummy;
	return newItr;
}


DataLinkedList::Iterator DataLinkedList::end() const {
	Iterator newItr;
	//newItr.setCurrNode(*m_tailDummy);
	newItr = *m_tailDummy;
	return newItr;
}

bool DataLinkedList::isEmpty() const {
	// list is empty if head dummy's next node is tail dummy
	if (m_headDummy->m_nextListNode == m_tailDummy) {
		return true; // head's next is tail, return true
	}
	return false; // the list holds valid nodes, list is not empty
}
